package com.ruoyi.business.listener;

import com.alibaba.fastjson.JSON;
import com.ruoyi.business.constant.TradeConstants;
import com.ruoyi.business.domain.BusinessTradeConfig;
import com.ruoyi.business.domain.BusinessTradeRecord;
import com.ruoyi.business.dto.TicketDTO;
import com.ruoyi.business.enumType.PSIceOrderState;
import com.ruoyi.business.enumType.PSIceOrderType;
import com.ruoyi.business.enumType.TriggerType;
import com.ruoyi.business.exception.TradeException;
import com.ruoyi.business.service.IBusinessTradeConfigService;
import com.ruoyi.business.service.IBusinessTradeRecordService;
import com.ruoyi.business.service.OnTicketHandler;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 当实时行情与开仓成交价相比
 * 止损做成静态止损
 * 止盈动态止盈
 */
@Component("profitOrLossStopSubscriber")
public class ProfitOrLossStopSubscriber implements OnTicketHandler {

    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(ProfitOrLossStopSubscriber.class);


    @Autowired
    private RedisCache redisCache;

    @Autowired
    private IBusinessTradeConfigService businessTradeConfigService;

    @Autowired
    private IBusinessTradeRecordService businessTradeRecordService;

    @Value("${trade.dynamicBottomRate}")
    private String dynamicBottomRate;

    private static final ConcurrentHashMap<String, BusinessTradeRecord> staticStopProfitMap = new ConcurrentHashMap<>();

    /**
     * @param message
     */
    @Override
    public synchronized void onTicket(String message) {
        logger.info("止盈止损,监听到消息：{}", message);

        try {
            List<TicketDTO> ticketDTOS = JSON.parseArray(message, TicketDTO.class);
            TicketDTO ticketDTO = ticketDTOS.get(0);
            BigDecimal price = new BigDecimal(String.valueOf(ticketDTO.getPrice()));

            if (price.compareTo(BigDecimal.ZERO) == 0) {
                return;
            }

            BusinessTradeConfig businessTradeConfigQuery = new BusinessTradeConfig();
            businessTradeConfigQuery.setStockCode(ticketDTO.getSymbol());
            businessTradeConfigQuery.setStatus(0);
            List<BusinessTradeConfig> businessTradeConfigs = businessTradeConfigService.selectBusinessTradeConfigList(businessTradeConfigQuery);
            if (businessTradeConfigs.size() == 0) {
                logger.error("配置策略数据为空");
                return;
            }
            Map<Long, BusinessTradeConfig> businessTradeConfigMap = businessTradeConfigs.stream().collect(Collectors.toMap(BusinessTradeConfig::getId, Function.identity()));

            List<BusinessTradeRecord> businessTradeRecordList = businessTradeRecordService.selectTodayTradeRecord();
            // 止盈止损只对开仓单 已成交和部分成交 或者 部分撤单的数据进行处理
            businessTradeRecordList = businessTradeRecordList.stream().filter(item -> TriggerType.AUTO_TAKE_POSITION_TRIGGER.equals(TriggerType.valueOf(item.getTriggerType()))).filter(item -> !item.getPositionClosed()).filter(item -> item.getDelegateState().equals(PSIceOrderState.Filled.value()) || item.getDelegateState().equals(PSIceOrderState.PartFilled.value())).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(businessTradeRecordList)) {
                for (BusinessTradeRecord businessTradeRecord : businessTradeRecordList) {
                    BusinessTradeConfig businessTradeConfig = businessTradeConfigMap.get(businessTradeRecord.getStrategyId());

                    if (Objects.isNull(businessTradeConfig)) {
                        logger.error("交易单据查询策略id不存在，businessTradeRecord.getStrategyId()：{}", businessTradeRecord.getStrategyId());
                        continue;
                    }
                    BigDecimal staticStopLossRate = businessTradeConfig.getStaticStopLossRate().multiply(new BigDecimal("0.01"));
                    // 止盈分动态和静态
                    BigDecimal dynamicStopProfitRate = null;
                    BigDecimal staticStopProfitRate = null;
                    if (Objects.nonNull(businessTradeConfig.getDynamicStopProfitRate())) {
                        dynamicStopProfitRate = businessTradeConfig.getDynamicStopProfitRate().multiply(new BigDecimal("0.01"));
                    }
                    if (Objects.nonNull(businessTradeConfig.getStaticStopProfitRate())) {
                        staticStopProfitRate = businessTradeConfig.getStaticStopProfitRate().multiply(new BigDecimal("0.01"));
                    }
                    BigDecimal dealPrice = businessTradeRecord.getDealPrice();
                    // 买
                    if (PSIceOrderType.Buy.value() == businessTradeRecord.getDelegateType()) {
                        // 判断对冲单，根据方向取值动态回撤比率
                        if(businessTradeConfig.getTradeHedge()){
                            // 对冲单 做多时动态止盈回撤
                            dynamicStopProfitRate = businessTradeConfig.getTradeHedgeSaleDynamicProfitRate().multiply(new BigDecimal("0.01"));
                            // todo 后期加上 对冲同步委托，和回撤比例对冲委托
                        }

                        if (price.compareTo(dealPrice) > 0) {
                            BigDecimal highPrice = redisCache.getCacheObject(TradeConstants.SYMBOL_PRICE_HIGH_KEY + businessTradeRecord.getOrderNo());

                            if (Objects.isNull(highPrice)) {
                                logger.error("未获取到行情最高价，key:{}", TradeConstants.SYMBOL_PRICE_HIGH_KEY + businessTradeRecord.getOrderNo());
                                throw new TradeException("未获取到行情最高价,key:" + TradeConstants.SYMBOL_PRICE_HIGH_KEY + businessTradeRecord.getOrderNo());
                            }
                            BigDecimal subtract = highPrice.subtract(price);
                            BigDecimal divide = subtract.divide(highPrice, 5, RoundingMode.HALF_UP);


                            BigDecimal subtractPrice = price.subtract(dealPrice);
                            BigDecimal staticProfitRate = subtractPrice.divide(dealPrice, 5, RoundingMode.HALF_UP);

                            // 静态止盈
                            if (Objects.nonNull(staticStopProfitRate) && staticProfitRate.compareTo(staticStopProfitRate) >= 0) {
                                // 没有动态止盈
                                if (Objects.isNull(dynamicStopProfitRate)) {
                                    doCancleBeforeTrade(businessTradeRecord);
                                    AjaxResult ajaxResult = businessTradeRecordService.doBusinessTradeByStopProfitOrLoss(businessTradeConfig.getId(), PSIceOrderType.Sell, businessTradeRecord, price, TriggerType.STATIC_STOP_PROFIT_TRIGGER);
                                    if ((int) ajaxResult.get(AjaxResult.CODE_TAG) == 200) {
                                        logger.info("静态止盈卖出成功，stopProfitBusinessRecord：{}", JSON.toJSONString(ajaxResult.get(AjaxResult.DATA_TAG)));
                                    } else {
                                        logger.info("静态止盈卖出失败，msg：{}", ajaxResult.get(AjaxResult.MSG_TAG));
                                    }
                                }
                                if (Objects.nonNull(dynamicStopProfitRate)) {
                                    // 记录达到静态止盈的单子
                                    staticStopProfitMap.put(businessTradeRecord.getOrderNo(), businessTradeRecord);
                                }
                            }
                            // 动态止盈
                            if (Objects.nonNull(dynamicStopProfitRate)) {
                                // 静态止盈为空
                                if (Objects.isNull(staticStopProfitRate)) {
                                    // 2倍的tradeRate 最低动态止盈条件
                                    BigDecimal dynamicBottomRatePrice = dealPrice.multiply(new BigDecimal(dynamicBottomRate).multiply(new BigDecimal("0.01")).add(BigDecimal.ONE));
                                    // 只存在动态止盈 动态止盈(保证最低盈利在配置最低赢利率之上)
                                    if (divide.compareTo(dynamicStopProfitRate) >= 0 && price.compareTo(dynamicBottomRatePrice) >= 0) {
                                        doCancleBeforeTrade(businessTradeRecord);
                                        logger.info("动态止盈卖出触发执行，动态止盈率：{},最高价：{},盘口价格：{},回撤比率：{}", dynamicStopProfitRate, highPrice, price, divide);
                                        AjaxResult ajaxResult = businessTradeRecordService.doBusinessTradeByStopProfitOrLoss(businessTradeConfig.getId(), PSIceOrderType.Sell, businessTradeRecord, price, TriggerType.DYNAMIC_STOP_PROFIT_TRIGGER);
                                        if ((int) ajaxResult.get(AjaxResult.CODE_TAG) == 200) {
                                            logger.info("动态止盈卖出成功，stopProfitBusinessRecord：{}", JSON.toJSONString(ajaxResult.get(AjaxResult.DATA_TAG)));
                                        } else {
                                            logger.info("动态止盈卖出失败，msg：{}", ajaxResult.get(AjaxResult.MSG_TAG));
                                        }
                                    }
                                } else {
                                    BusinessTradeRecord businessTradeRecord1 = staticStopProfitMap.get(businessTradeRecord.getOrderNo());
                                    logger.info("动态止盈卖出获取行情达到静态止盈率单据：{}", JSON.toJSONString(businessTradeRecord1));
                                    // 如果该单据达到静态止盈率并且回撤满足
                                    if (Objects.nonNull(businessTradeRecord1) && divide.compareTo(dynamicStopProfitRate) >= 0) {
                                        doCancleBeforeTrade(businessTradeRecord);
                                        logger.info("动态止盈卖出触发执行，动态止盈率：{},最高价：{},盘口价格：{},回撤比率：{}", dynamicStopProfitRate, highPrice, price, divide);
                                        AjaxResult ajaxResult = businessTradeRecordService.doBusinessTradeByStopProfitOrLoss(businessTradeConfig.getId(), PSIceOrderType.Sell, businessTradeRecord, price, TriggerType.DYNAMIC_STOP_PROFIT_TRIGGER);
                                        if ((int) ajaxResult.get(AjaxResult.CODE_TAG) == 200) {
                                            logger.info("动态止盈卖出成功，stopProfitBusinessRecord：{}", JSON.toJSONString(ajaxResult.get(AjaxResult.DATA_TAG)));
                                            staticStopProfitMap.remove(businessTradeRecord.getOrderNo());
                                        } else {
                                            logger.info("动态止盈卖出失败，msg：{}", ajaxResult.get(AjaxResult.MSG_TAG));
                                        }
                                    }
                                }
                            }


                        } else if (price.compareTo(dealPrice) < 0) {
                            BigDecimal subtract = dealPrice.subtract(price);
                            BigDecimal divide = subtract.divide(dealPrice, 5, RoundingMode.HALF_UP);
                            // 止损
                            if (divide.compareTo(staticStopLossRate) >= 0) {
                                doCancleBeforeTrade(businessTradeRecord);
                                AjaxResult ajaxResult = businessTradeRecordService.doBusinessTradeByStopProfitOrLoss(businessTradeConfig.getId(), PSIceOrderType.Sell, businessTradeRecord, price, TriggerType.STATIC_STOP_LOSS_TRIGGER);
                                if ((int) ajaxResult.get(AjaxResult.CODE_TAG) == 200) {
                                    logger.info("静态止损卖出成功，stopProfitBusinessRecord：{}", JSON.toJSONString(ajaxResult.get(AjaxResult.DATA_TAG)));
                                } else {
                                    logger.info("静态止损卖出失败，msg：{}", ajaxResult.get(AjaxResult.MSG_TAG));
                                }
                            }
                        }

                    }
                    // 卖
                    if (PSIceOrderType.Sell.value() == businessTradeRecord.getDelegateType()) {
                        // 判断对冲单，根据方向取值动态回撤比率
                        if(businessTradeConfig.getTradeHedge()){
                            // 对冲单 做空时动态止盈回撤
                            dynamicStopProfitRate = businessTradeConfig.getTradeHedgeSellDynamicProfitRate().multiply(new BigDecimal("0.01"));
                        }
                        if (price.compareTo(dealPrice) > 0) {
                            BigDecimal subtract = price.subtract(dealPrice);
                            BigDecimal divide = subtract.divide(dealPrice, 5, RoundingMode.HALF_UP);
                            // 止损
                            if (divide.compareTo(staticStopLossRate) >= 0) {
                                doCancleBeforeTrade(businessTradeRecord);
                                AjaxResult ajaxResult = businessTradeRecordService.doBusinessTradeByStopProfitOrLoss(businessTradeConfig.getId(), PSIceOrderType.Buy, businessTradeRecord, price, TriggerType.STATIC_STOP_LOSS_TRIGGER);
                                if ((int) ajaxResult.get(AjaxResult.CODE_TAG) == 200) {
                                    logger.info("静态止损买入成功，stopProfitBusinessRecord：{}", JSON.toJSONString(ajaxResult.get(AjaxResult.DATA_TAG)));
                                } else {
                                    logger.info("静态止损买入失败，msg：{}", ajaxResult.get(AjaxResult.MSG_TAG));
                                }
                            }
                        } else if (price.compareTo(dealPrice) < 0) {


                            BigDecimal lowPrice = redisCache.getCacheObject(TradeConstants.SYMBOL_PRICE_LOW_KEY + businessTradeRecord.getOrderNo());

                            if (Objects.isNull(lowPrice)) {
                                logger.error("未获取到行情最低价，key:{}", TradeConstants.SYMBOL_PRICE_HIGH_KEY + businessTradeRecord.getOrderNo());
                                throw new TradeException("未获取到行情最低价,key:" + TradeConstants.SYMBOL_PRICE_HIGH_KEY + businessTradeRecord.getOrderNo());
                            }

                            BigDecimal subtract = price.subtract(lowPrice);
                            BigDecimal divide = subtract.divide(lowPrice, 5, RoundingMode.HALF_UP);

                            BigDecimal subtractPrice = dealPrice.subtract(price);
                            BigDecimal staticProfitRate = subtractPrice.divide(dealPrice, 5, RoundingMode.HALF_UP);


                            // 静态止盈
                            if (Objects.nonNull(staticStopProfitRate) && staticProfitRate.compareTo(staticStopProfitRate) >= 0) {
                                // 没有动态止盈
                                if (Objects.isNull(dynamicStopProfitRate)) {
                                    doCancleBeforeTrade(businessTradeRecord);
                                    AjaxResult ajaxResult = businessTradeRecordService.doBusinessTradeByStopProfitOrLoss(businessTradeConfig.getId(), PSIceOrderType.Buy, businessTradeRecord, price, TriggerType.STATIC_STOP_PROFIT_TRIGGER);
                                    if ((int) ajaxResult.get(AjaxResult.CODE_TAG) == 200) {
                                        logger.info("静态止盈买入出成功，stopProfitBusinessRecord：{}", JSON.toJSONString(ajaxResult.get(AjaxResult.DATA_TAG)));
                                    } else {
                                        logger.info("静态止盈买入失败，msg：{}", ajaxResult.get(AjaxResult.MSG_TAG));
                                    }
                                }

                                if (Objects.nonNull(dynamicStopProfitRate)) {
                                    // 记录达到静态止盈的单子
                                    staticStopProfitMap.put(businessTradeRecord.getOrderNo(), businessTradeRecord);

                                }

                            }
                            // 动态止盈
                            if (Objects.nonNull(dynamicStopProfitRate)) {
                                // 静态止盈为空
                                if (Objects.isNull(staticStopProfitRate)) {
                                    // dynamicBottomRate 最低动态止盈条件
                                    BigDecimal dynamicBottomRatePrice = dealPrice.multiply(BigDecimal.ONE.subtract(new BigDecimal(dynamicBottomRate).multiply(new BigDecimal("0.01"))));
                                    // 只存在动态止盈 动态止盈(保证最低盈利在配置最低赢利率之上)
                                    if (divide.compareTo(dynamicStopProfitRate) >= 0 && price.compareTo(dynamicBottomRatePrice) <= 0) {
                                        doCancleBeforeTrade(businessTradeRecord);
                                        logger.info("动态止盈买入触发执行，动态止盈率：{},最低价：{},盘口价格：{},回撤比率：{}", dynamicStopProfitRate, lowPrice, price, divide);
                                        AjaxResult ajaxResult = businessTradeRecordService.doBusinessTradeByStopProfitOrLoss(businessTradeConfig.getId(), PSIceOrderType.Buy, businessTradeRecord, price, TriggerType.DYNAMIC_STOP_PROFIT_TRIGGER);
                                        if ((int) ajaxResult.get(AjaxResult.CODE_TAG) == 200) {
                                            logger.info("动态止盈买入成功，stopProfitBusinessRecord：{}", JSON.toJSONString(ajaxResult.get(AjaxResult.DATA_TAG)));
                                        } else {
                                            logger.info("动态止盈买入失败，msg：{}", ajaxResult.get(AjaxResult.MSG_TAG));
                                        }
                                    }

                                } else {
                                    BusinessTradeRecord businessTradeRecord1 = staticStopProfitMap.get(businessTradeRecord.getOrderNo());
                                    logger.info("动态止盈买入获取行情达到静态止盈率单据：{}", JSON.toJSONString(businessTradeRecord1));
                                    // 如果该单据达到静态止盈率并且回撤满足
                                    if (Objects.nonNull(businessTradeRecord1) && divide.compareTo(dynamicStopProfitRate) >= 0) {
                                        doCancleBeforeTrade(businessTradeRecord);
                                        logger.info("动态止盈买入触发执行，动态止盈率：{},最低价：{},盘口价格：{},回撤比率：{}", dynamicStopProfitRate, lowPrice, price, divide);
                                        AjaxResult ajaxResult = businessTradeRecordService.doBusinessTradeByStopProfitOrLoss(businessTradeConfig.getId(), PSIceOrderType.Buy, businessTradeRecord, price, TriggerType.DYNAMIC_STOP_PROFIT_TRIGGER);
                                        if ((int) ajaxResult.get(AjaxResult.CODE_TAG) == 200) {
                                            logger.info("动态止盈买入成功，stopProfitBusinessRecord：{}", JSON.toJSONString(ajaxResult.get(AjaxResult.DATA_TAG)));
                                            staticStopProfitMap.remove(businessTradeRecord.getOrderNo());
                                        } else {
                                            logger.info("动态止盈买入失败，msg：{}", ajaxResult.get(AjaxResult.MSG_TAG));
                                        }
                                    }

                                }
                            }

                        }
                    }
                }
            } else {
                logger.info("止盈止损：未获取到当日开仓数据或开仓后还未成交或开仓单已结束：{}", message);
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("静态止盈止损失败：{}", e.getMessage());
        }

    }

    private void doCancleBeforeTrade(BusinessTradeRecord businessTradeRecord) {
        // 如果有部分成交，则需要先撤单
        if (PSIceOrderState.PartFilled.value() == businessTradeRecord.getDelegateState()) {
            businessTradeRecordService.cancleOrder(businessTradeRecord);
        }
    }

}

